#ifndef __DECIDER_MACRO__
#define __DECIDER_MACRO__

#include <string>

#include "dependence/common_macro.h"

namespace decider {

#define ADDSUB_DECIDERS_STATEMENT_1(_1) AddSubDecider(std::make_shared<_1>());

#define ADDSUB_DECIDERS_STATEMENT_2(_1, _2) \
    ADDSUB_DECIDERS_STATEMENT_1(_1)         \
    ADDSUB_DECIDERS_STATEMENT_1(_2)

#define ADDSUB_DECIDERS_STATEMENT_3(_1, _2, _3) \
    ADDSUB_DECIDERS_STATEMENT_1(_1)             \
    ADDSUB_DECIDERS_STATEMENT_2(_2, _3)

#define ADDSUB_DECIDERS_STATEMENT_4(_1, _2, _3, _4) \
    ADDSUB_DECIDERS_STATEMENT_1(_1)                 \
    ADDSUB_DECIDERS_STATEMENT_3(_2, _3, _4)

#define ADDSUB_DECIDERS_STATEMENT_5(_1, _2, _3, _4, _5) \
    ADDSUB_DECIDERS_STATEMENT_1(_1)                     \
    ADDSUB_DECIDERS_STATEMENT_4(_2, _3, _4, _5)

#define ADDSUB_DECIDERS_STATEMENT_6(_1, _2, _3, _4, _5, _6) \
    ADDSUB_DECIDERS_STATEMENT_1(_1)                         \
    ADDSUB_DECIDERS_STATEMENT_5(_2, _3, _4, _5, _6)

#define ADDSUB_DECIDERS_STATEMENT_7(_1, _2, _3, _4, _5, _6, _7) \
    ADDSUB_DECIDERS_STATEMENT_1(_1)                             \
    ADDSUB_DECIDERS_STATEMENT_6(_2, _3, _4, _5, _6, _7)

#define ADDSUB_DECIDERS_STATEMENT_8(_1, _2, _3, _4, _5, _6, _7, _8) \
    ADDSUB_DECIDERS_STATEMENT_1(_1)                                 \
    ADDSUB_DECIDERS_STATEMENT_7(_2, _3, _4, _5, _6, _7, _8)

#define ADDSUB_DECIDERS_STATEMENT_9(_1, _2, _3, _4, _5, _6, _7, _8, _9) \
    ADDSUB_DECIDERS_STATEMENT_1(_1)                                     \
    ADDSUB_DECIDERS_STATEMENT_8(_2, _3, _4, _5, _6, _7, _8, _9)

#define ADDSUB_DECIDERS_STATEMENT_10(_1, _2, _3, _4, _5, _6, _7, _8, _9, _10) \
    ADDSUB_DECIDERS_STATEMENT_1(_1)                                           \
    ADDSUB_DECIDERS_STATEMENT_9(_2, _3, _4, _5, _6, _7, _8, _9, _10)

#define ADDSUB_DECIDERS_STATEMENT(...) \
    SYMBOL_CATENATE_WITH_MACRO(ADDSUB_DECIDERS_STATEMENT_, COUNT_PARMS(__VA_ARGS__))(__VA_ARGS__)

#define DECLARE_DEFAULT_DECIDER                   \
    class DefaultDecider : public Decider {       \
      public:                                     \
        DefaultDecider() : Decider() {            \
            Init();                               \
        }                                         \
        inline std::string DeciderID() {          \
            return std::string{"DefaultDecider"}; \
        }                                         \
                                                  \
      public:                                     \
        void Init();                              \
        auto Ready() -> bool;                     \
        auto TryProcess() -> bool;                \
        auto Process() -> _Status;                \
    };

#define DECLARE_DECIDER(name, ...)                    \
    class name : public Decider {                     \
      public:                                         \
        name() : Decider() {                          \
            ADDSUB_DECIDERS_STATEMENT(DefaultDecider) \
            ADDSUB_DECIDERS_STATEMENT(__VA_ARGS__);   \
            Init();                                   \
        }                                             \
        inline std::string DeciderID() {              \
            return #name;                             \
        }                                             \
                                                      \
      public:                                         \
        virtual void Init();                          \
        virtual auto Ready() -> bool;                 \
        virtual auto TryProcess() -> bool;            \
        virtual auto Process() -> _Status;            \
    };


#define DECLARE_DECIDER_FINAL(name)                   \
    class name : public Decider {                     \
      public:                                         \
        name() : Decider() {                          \
            ADDSUB_DECIDERS_STATEMENT(DefaultDecider) \
            Init();                                   \
        }                                             \
        inline std::string DeciderID() {              \
            return #name;                             \
        }                                             \
                                                      \
      public:                                         \
        void Init();                                  \
        auto Ready() -> bool;                         \
        auto TryProcess() -> bool;                    \
        auto Process() -> _Status;                    \
    };

} // namespace decider

#endif // __DECIDER_MACRO__